<?php

namespace catchAdmin\storehouse\model;

use catchAdmin\stock\model\Stock;
use catchAdmin\stock\model\WarehouseConfig;
use catchAdmin\storehouse\model\search\WarehousingSonSearch;
use catcher\base\CatchModel;
use catcher\CatchAuth;
use catcher\CatchResponse;
use think\Exception;
use think\exception\HttpException;
use think\facade\Db;
/**
 *
 * @property int $id
 * @property string $warehousing_id
 * @property string $warehousing_son_id
 * @property string $goods_id
 * @property string $HSCODE
 * @property string $goods_name
 * @property string $goods_Cname
 * @property string $goods_Ename
 * @property string $supplier_id
 * @property string $supplier_name
 * @property string $manufacturer_id
 * @property string $manufacturer_name
 * @property string $packing_id
 * @property string $p_barcode
 * @property float $packing_num
 * @property string $dictionary_name
 * @property string $batch_number
 * @property int $number
 * @property int $box_number
 * @property int $tray_number
 * @property int $isstatus
 * @property int $sort
 * @property int $created_at
 * @property int $updated_at
 * @property string $status
 * @property int $deleted_at
 * @property int $actual_number
 * @property int $tenant_id
 * @property int $creator_id
 */
class WarehousingSon extends CatchModel
{
    use WarehousingSonSearch;
    
    public $field = [
        // ID
        'id',
        // 入库主单编号
        'warehousing_id',
        // 入库明细编号
        'warehousing_son_id',
        // 商品编号
        'goods_id',
        // HSCODE
        'HSCODE',
        // 商品名称
        'goods_name',
        // 商品中文名称
        'goods_Cname',
        // 商品英文名称
        'goods_Ename',
        // 供应商编号
        'supplier_id',
        // 供应商名称
        'supplier_name',
        // 制造商编号
        'manufacturer_id',
        // 制造商名称
        'manufacturer_name',
        // 包装编号
        'packing_id',
        // 包装条形码
        'p_barcode',
        // 包装数量
        'packing_num',
        // 包装单位级别名称
        'unit_name',
        // 项号
        'batch_number',
        // 商品数量
        'number',
        // 商品箱数
        'box_number',
        // 托盘数
        'tray_number',
        // 数据状态0=关闭,1=开启
        'isstatus',
        // 排序
        'sort',
        // 创建时间
        'created_at',
        // 更新时间
        'updated_at',
        // 入库状态:0=未入库,1=全部入库,2=部分入库
        'status',
        // 删除时间
        'deleted_at',
        // 入库数量
        'actual_number',
        // 商户
        'tenant_id',
        // 创建人id
        'creator_id',
        'lot01',
        'lot02',
        'specification',
        'warehousing_son_config_attribute',//入库订单前台提交的库位属性
        'PO',
        'DO',
        'SN',
        'CO',
        'LOT3'
    ];
    
    public $name = 'db_warehousing_son';
    /**
   * 列表
   * @throws \think\db\exception\DbException
   * @return \think\Paginator
   */
    public function getList($tenant_id = 0)
    {
        $where = [];
        if($tenant_id !== 0){
            $where[]=['tenant_id','=',$tenant_id];
        }
         return $this->catchSearch()
                    ->order('id','desc')
                    ->where($where)
                    ->field('id,goods_id,packing_num,unit_name,goods_name,goods_Cname,creator_id,warehousing_id,warehousing_son_id,batch_number,number,box_number,tray_number,created_at,status,actual_number,lot01,lot02,enter_type,packing_id,warehousing_son_config_attribute,PO,DO,CO,SN,LOT1,LOT2,LOT3')
                    ->paginate()
             ->each(function (&$item){
                 $item['username'] = Db::table('users')->where('id',$item['creator_id'])->value('username');
                 $item['packingInfo'] = Db::table('db_packing')->field('layup_num,unit_name,packing_num')->where('packing_id',$item['packing_id'])->find();

                 $product = Db::table('db_product')->field('sku,packing_id,describe,goods_Cname,goods_Ename,HSCODE,new_item_number')->where('goods_name',$item['goods_name'])->find();
                 $item['goods_Cname'] = $product['goods_Cname'];
                 $item['goods_Ename'] = $product['goods_Ename'];
                 $item['HSCODE'] = $product['HSCODE'];
                 $item['new_item_number'] = $product['new_item_number'];
                 $item['describe'] = $product['describe'];
                 $item['sku'] = $product['sku'];
                 $packing_id = explode(',',$product['packing_id']);
                 $where = [];
                 $where[] = ['packing_id','in',$packing_id];
                 $list = Db::table('db_packing')->field('packing_id,unit_name,packing_num,layup_num')->where($where)->select()->toArray();
                 foreach ($list as $k=>$v){
                     $list[$k]['value'] = $v['packing_id'];
                     $list[$k]['label'] = '1/'.$v['layup_num'].'/'.$v['packing_num'].'(托/箱/件)';
                     //$list[$k]['label'] = '包装数量('.$v['packing_num'].')--包装单位('.$v['unit_name'].')--托盘可放置' . $v['layup_num']  . $v['unit_name'];
                 }
                 $item['packing_list'] = $list;
                 $warehousing_son_config_attribute = explode(',',$item['warehousing_son_config_attribute']);
                 $config_parent_info = Db::table('db_warehouse_config')->field('parent_id,name')->where('id',$warehousing_son_config_attribute[1])->find();
                 $item['checked_config'] = [(int) $config_parent_info['parent_id'],(int)$warehousing_son_config_attribute[1]];
                 $item['config_parent_info'] = $config_parent_info;
                 $item['checked_config_status'] = $warehousing_son_config_attribute[0];
             });
    }

    //根据商品ID，数量   创建入库子订单，自动分配托盘，和库位
    public function autoConversionByGidNum($goods_id,$autoConversionParams=[]){

        $user = (new CatchAuth)->user();

        $goodsInfo =Db::table('db_product')->where('goods_id',$goods_id)->find();

        //分配库位

        //判断是否是专属商品（专属商品，只能放置在隔离区，暂放区）
        $goods_type = 1;


        //普通商品，只能繁放在（存储，赞放区）
        //1。拉取没删除的
//        throw new Exception('2341');

        if(1 == $goods_type){
            $where  = [];
            $where[] =  ['deleted_at','=',0];
            $where[] = ['tenant_id','=',$user->tenant_id];
//            $where[] = ['level','<',3];

            $field = ['config_id','name','level','parent_id','id'];
            $warehouse_config =  Db::table('db_warehouse_config')
                ->field($field)->where($where)
                ->order('sort','desc')->select()->toArray();
        }

        $warehouse_config = $this->generateTree($warehouse_config,0);

        $warehouse_config_new_arr = [];
        foreach ($warehouse_config as $value){
            foreach ($value['son'] as $v1){
//                $warehouse_config_new_arr[] = $v1;
                foreach ($v1['son'] as $vv1){
                    $warehouse_config_new_arr[] = $vv1;
                }
            }
        }


        $autoConversionTrayArr = [];
        foreach ($warehouse_config_new_arr as $value) {
            $map = [];
            $map[] = ['status', '<>', 1];
            $map[] = ['config_id', '=', $value['config_id']];

            $res = Db::table('db_stock')->field('sum(number) as s_num,sum(out_number) as s_out')->where($map)->find();

            $stock_actual_num = $res['s_num'] - $res['s_out'];

            if ($stock_actual_num <= 0) {//可用
                $autoConversionTrayArr[] = $value['config_id'];
                if (count($autoConversionTrayArr) == $autoConversionParams['tray_num']) {
                    break;
                }
            }
        }

        $insertData = [];
        $product = [];

        $tempNum = $autoConversionParams['total_num'];
        for ($i =0;$i<count($autoConversionTrayArr);$i++){
            $randomTrayId = 't'.date('YmdHis') . rand(1000,9990);

            $tray_data = [
                'warehousing_id'=>$autoConversionParams['warehousing_id'],
                'warehousing_son_id'=>$autoConversionParams['warehousing_son_id'],
                'tray_id'=>$randomTrayId,
//                'config_id'=>$value['config_id'],
                'config_id'=>$autoConversionTrayArr[$i],
                'created_at'=>time(),
                'updated_at'=>time(),
                'status'=>0,//未入库
                'goods_status'=>'Good',
                'deleted_at'=>0,
                'creator_id'=>$user->id,
                'tenant_id'=>$user->tenant_id,
                'batch_number'=>$autoConversionParams['batch_number']
            ];

            if($tempNum >= $autoConversionParams['packing_num'] * $autoConversionParams['packing_layup_num']){
                $tray_data['box_number'] = $autoConversionParams['packing_layup_num'];
                $tray_data['number'] = $autoConversionParams['packing_num'] * $autoConversionParams['packing_layup_num'];
                $tempNum -= $tray_data['number'];
            }else{
                $tempSy = $tempNum % $autoConversionParams['packing_num'];
                $tray_data['box_number'] =  $tempSy == 0
                    ? ($tempNum / $autoConversionParams['packing_num'])
                    : ($tempNum > $autoConversionParams['packing_num'] ? floor($tempNum / $autoConversionParams['packing_num']) + 1 : 1);
                $tray_data['number'] = $tempNum;
            }

            $insertData[] = $tray_data;

            //产品
            //product
            $product[$i]['warehousing_id']=$autoConversionParams['warehousing_id'];
            $product[$i]['warehousing_son_id']=$autoConversionParams['warehousing_son_id'];
            $product[$i]['goods_name']=$goodsInfo['goods_name'];
            $product[$i]['goods_id']=$goodsInfo['goods_id'];
            $product[$i]['goods_Cname']=$goodsInfo['goods_Cname'];
            $product[$i]['goods_Ename']=$goodsInfo['goods_Ename'];
            $product[$i]['manufacturer_id']=$goodsInfo['manufacturer_id'];
            $product[$i]['manufacturer_name']=Db::table('db_manufacturer')->where('manufacturer_id',$goodsInfo['manufacturer_id'])->value('manufacturer_name');
            $product[$i]['supplier_id']=$goodsInfo['supplier_id'];
            $product[$i]['supplier_name']=Db::table('db_supplier')->where('supplier_id',$goodsInfo['supplier_id'])->value('supplier_name');
            $product[$i]['packing_id']=$autoConversionParams['packing_id'];
            $product[$i]['p_barcode']=$autoConversionParams['packing_id'];
            $packing=Db::table('db_packing')->where('packing_id',$autoConversionParams['packing_id'])->find();
            $product[$i]['packing_num']=$packing['packing_num'];
            $product[$i]['unit_name']=$packing['unit_name'];
            $product[$i]['number']= $tray_data['number'];
            $product[$i]['box_number']= $tray_data['box_number'];
            $product[$i]['created_at']=time();
            $product[$i]['tenant_id']=$user['tenant_id'];
            $product[$i]['creator_id']=$user['id'];
            $product[$i]['tray_id']= $randomTrayId;
            $product[$i]['specification']=$packing['packing_num'].' / '.$packing['unit_name'] . ' / ' .  $packing['layup_num'];
        }


        //  $data[$k]['stock']=$arr['s_num']-$arr['s_out'];

        //return $autoConversionTrayArr;

        //return array_merge($insertData,$product);

        //加事物

        Db::startTrans();
        try {
            //写入托盘数据
            Db::table('db_tray')->insertAll($insertData);
            //写入入库托盘产品表
            Db::table('db_warehousing_product')->insertAll($product);

            Db::commit();
        }catch (\Exception $exception) {
            Db::rollback();
            throw new Exception('系统自动分配库位托盘失败11' . $exception->getMessage());
        }


        return true;

    }

    public function generateTree($data,$parent_id = 0)
    {
        $tree = [];
        $newData = array_combine(array_column($data,'id'),$data);

        foreach ($newData as $key => $datum) {
            $newData[$key]['value'] = $datum['id'];
            $newData[$key]['label'] = $datum['name'];
            if ($datum['parent_id'] == $parent_id) {
                //根节点直接把地址放到新数组中
                $tree[] = &$newData[$key];
            } else {
                //不是根节点的将自己的地址放到父级的child节点
                $newData[$datum['parent_id']]['children'][] = &$newData[$key];
                //$newData[$datum['parent_id']]['son'][] = &$newData[$key];
            }
        }
        return $tree;
    }

    public function digui($array, $parent_id=0){

        $list = [];
        foreach ($array as &$value) {
            if ($value['parent_id'] == $parent_id) {
                if(!empty($lst =  $this->digui($array, $value['id']))){
                    $value['children'] = $lst;
                    $value['son'] = $lst;
                }

                $list[] = $value;
            }
        }
        return $list;
    }


    //2-----根据入库订单明细表，数量   创建入库子订单，自动分配托盘，和库位
    public function autoConversionByWsonID($son_id){
        $user = (new CatchAuth)->user();
        //1.拿到明细表，判断是否是子集的订单 所以传入tanant_id
        $warehousing_son = Db::table('db_warehousing_son')->where('warehousing_son_id',$son_id)->find();
        //2.拿到订单主表
        $warehousing = Db::table('db_warehousing')->where('warehousing_id',$warehousing_son['warehousing_id'])->find();

        $project_id =  Db::table('db_project')->where('project_id',$warehousing['project_client'])->value('id');

        //项目所选
        $warehouse_config_list = (new WarehouseConfig)->getProjectWarehouseConfigListByPid($project_id);
        $warehouse_config_list_tree = (new WarehouseConfig)->generateTree($warehouse_config_list);


        $tray_list = Db::table('db_tray')->where([
            ['deleted_at','=',0,],
            ['warehousing_son_id','=',$son_id]
        ])->select()->toArray();

        if(!empty($tray_list)){//说明托盘有数据，直接取托盘数据

            foreach ($tray_list as $t_k => &$t_value){
                $config_res = Db::table('db_warehouse_config')->where('config_id',$t_value['config_id'])->find();

                $config_level2 = Db::table('db_warehouse_config')->field('id,config_id,parent_id')->where('id',$config_res['parent_id'])->find();

                $config_level1 =  Db::table('db_warehouse_config')->where('id',$config_level2['parent_id'])->value('config_id');

                $t_value['config1'][] = $config_level1;
                $t_value['config1'][] = $config_level2['config_id'];

                $t_value['config2'] = $config_res['config_id'];
                $t_value['configData2'] = Db::table('db_warehouse_config')->field('name,config_id')->where([
                    ['id','=',$config_res['id']],
                    ['isstatus','=',1]
                ])->select()->toArray();
            }

            return [
                'tray_info'=>$tray_list,
                'warehouse_config_info'=> $warehouse_config_list_tree,
                'Notification'=>'',
                'support_yfp'=>false//是否继续支持预分配数据
            ];
        }

        $warehousing_son_config_attribute = explode(',',$warehousing_son['warehousing_son_config_attribute']);
        $son_usage = $warehousing_son_config_attribute[0];
        $son_level_2 = $warehousing_son_config_attribute[1];

        //根据分区ID，project_id拿到所有授权的分组，然后再选出 son_usage
        $project_warehouse_config = Db::table('db_project_warehouse_config')
            ->where(['deleted_at'=>0,'project_id'=>$project_id,'config_level_2'=>$son_level_2])
            ->select()->toArray();

        if(empty($project_warehouse_config)){
            //说明之前的数据
            throw new Exception('老项目没有选择库区，请项目修改库位后，再入库');
        }
        //判断记录中是否有全选记录
        $project_all_level3_id = [];
        foreach ($project_warehouse_config as $value){
            if(0 == $value['config_level_3']){//说明全选了，我要拿到所有库位ID
                $level3_ids = Db::table('db_warehouse_config')
                    ->field('id')
                    ->where(['deleted_at'=>0,'parent_id'=>$value['config_level_2'],'level'=>3,'isstatus'=>1])
                    ->select()->toArray();
                $level3_ids = array_column($level3_ids,'id');
                $project_all_level3_id = array_merge($project_all_level3_id,$level3_ids);
            }else{
                $project_all_level3_id[] = $value['config_level_3'];
            }
        }

        //
        //dd($project_all_level3_id);

        //根据子订单，判断需要几个托盘，也就是几个库位
        //把之前usage null的数据处理一下
        $usage_config_arr = Db::table('db_warehouse_config')
            ->where('id','in',$project_all_level3_id)
            ->where('usage','=',$son_usage)
            ->where('isstatus','=',1)
            ->select()->toArray();


        //优化1-过程
        $_usage_config_arr_config_ids = array_column($usage_config_arr,'config_id');
        $_usage_config_arr_config_ids_stock = (new Stock)->where([
            ['status', '<>', 1],
            ['config_id', 'in', $_usage_config_arr_config_ids],
        ])->field('sum(Good_Qty + Hold_Qty + NG_Qty) as stock,config_id')->select()->toArray();
        $_usage_config_arr_config_ids_stock2 = array_column($_usage_config_arr_config_ids_stock,null,'config_id');

        //优化2-过程
        $_tray_weiruku_config = (new Tray)
            ->field('config_id,id')
            ->where([
            ['deleted_at','=',0],
            ['status','=',0],//有未入库的
            ['config_id','in',$_usage_config_arr_config_ids]
        ])->group('config_id')->select()->toArray();
        $_tray_weiruku_config_2 = array_column($_tray_weiruku_config,null,'config_id');

        //还要判断这几个库位是否是空的，再过滤一边
        foreach ($usage_config_arr as $key => &$value){

//            //1。已入库判断库存
//            $map = [];
//            $map[] = ['status', '<>', 1];
//            $map[] = ['config_id', '=', $value['config_id']];
//            $res = Db::table('db_stock')->field('sum(Good_Qty + Hold_Qty + NG_Qty) as stock')->where($map)->find();
//            $stock_actual_num = (int)$res['stock'];
//            if ($stock_actual_num > 0) {//不可用
//                unset($usage_config_arr[$key]);
//                continue;
//            }

            //优化1 - 修改后
            if(array_key_exists($value['config_id'],$_usage_config_arr_config_ids_stock2)
                &&
            ((int) $_usage_config_arr_config_ids_stock2[$value['config_id']]['stock'] > 0)){
                unset($usage_config_arr[$key]);
                continue;
            }


//            ///2。未入库，判断托盘-----------这里判断  托盘上面是否存在记录（）  是否已经被其他子订单预分配，如果分配了，就不要这个库位了//
//            $tray_weiruku_config = Db::table('db_tray')->where([
//                ['deleted_at','=',0],
//                ['status','=',0],//有未入库的
//                ['config_id','=',$value['config_id']]
//            ])->find();
//
//            if(!empty($tray_weiruku_config)){
////                dd($tray_weiruku_config);
//                unset($usage_config_arr[$key]);
//            }

            //优化2 -修改后
            if(array_key_exists($value['config_id'],$_tray_weiruku_config_2)){
                unset($usage_config_arr[$key]);
            }

        }
        $usage_config_arr = array_values($usage_config_arr);//优先选择
        $other_all_usage_config_arr = [];//备用

        //开始干活

//        dd($usage_config_arr);

        //正常来讲，如果tray_number 计算没问题，直接拿托盘数量
        if(0 < $needNewCounts =  $warehousing_son['tray_number'] - count($usage_config_arr)){//不够

            //dd($needNewCounts);

            $usage_level_2_data = Db::table('db_warehouse_config')->find($son_level_2);

//            $message = $usage_level_2_data['name'] . '可用空库位只有' . count($usage_config_arr) . "<br />实际需要库位数量：" . $warehousing_son['tray_number'];
//            throw new Exception($message);

            //不够的话，那么我们就开始试试别的库区是否满足

            //把别的库区可用的都拿出来

            //根据分区ID，project_id拿到所有授权的分组，然后再选出 son_usage
            $project_other_warehouse_config = Db::table('db_project_warehouse_config')
                ->where([
                    ['deleted_at','=',0],
                    ['project_id','=',$project_id],
//直接拉出所有数据
                    ['config_level_2','<>',$son_level_2],//其他所有的数据
                ])
                ->select()->toArray();


            if(!empty($project_other_warehouse_config)){//存在其他的库位

                //判断记录中是否有全选记录
                $project_other_all_level3_id = [];
                foreach ($project_other_warehouse_config as $other_value){
                    if(0 == $other_value['config_level_3']){//说明全选了，我要拿到所有库位ID
                        $other_level3_ids = Db::table('db_warehouse_config')
                            ->field('id')
                            ->where(['deleted_at'=>0,'parent_id'=>$other_value['config_level_2'],'level'=>3,'isstatus'=>1])
                            ->select()->toArray();
                        $other_level3_ids = array_column($other_level3_ids,'id');
                        $project_other_all_level3_id = array_merge($project_other_all_level3_id,$other_level3_ids);
                    }else{
                        $project_other_all_level3_id[] = $other_value['config_level_3'];
                    }
                }



                ///-------
                ///
                ///
                ///
                $all_usage_config_arr = Db::table('db_warehouse_config')
                    ->where('id','in',$project_other_all_level3_id)
                    ->where('usage','=',$son_usage)
                    ->where('isstatus','=',1)
                    ->select()->toArray();



                //还要判断这几个库位是否是空的，再过滤一边
                $needNewCountsI = 0;
                foreach ($all_usage_config_arr as $all_key => &$all_value){
                    ///1.判断库位是否有库存
                    $map = [];
                    $map[] = ['status', '<>', 1];
                    $map[] = ['config_id', '=', $all_value['config_id']];

                    $res = Db::table('db_stock')->field('sum(Good_Qty + Hold_Qty + NG_Qty) as stock')->where($map)->find();
                    $stock_actual_num = (int)$res['stock'];
                    if ($stock_actual_num > 0) {//不可用
                        unset($all_usage_config_arr[$all_key]);
                        continue;
                    }

                    ///2。未入库，判断托盘-----------这里判断  托盘上面是否存在记录（）  是否已经被其他子订单预分配，如果分配了，就不要这个库位了//
                    $tray_weiruku_config = Db::table('db_tray')->where([
                        ['deleted_at','=',0],
                        ['status','=',0],//有未入库的
                        ['config_id','=',$all_value['config_id']]
                    ])->find();

                    if(!empty($tray_weiruku_config)){
                        unset($all_usage_config_arr[$all_key]);
                    }

                    if(++$needNewCountsI >= $needNewCounts){//够数量，直接跳出。
                        break;
                    }

                }
                $other_all_usage_config_arr = array_values($all_usage_config_arr);
            }

        }

        //所有库位
        $all_config_data = array_merge($usage_config_arr,$other_all_usage_config_arr);

        //分配
        //
        $tempNum = $warehousing_son['number'];//子订单总入库数量
        $packing = Db::table('db_packing')->where('packing_id',$warehousing_son['packing_id'])->find();

        $returnArr = [];
        foreach ($all_config_data as $k1 => $v1){
            //0 1 2
            if($warehousing_son['tray_number'] == $k1 ){
                break;
            }

            $tray_data = [
                'goods_status'=>'Good',
                'tray_id'=>''
            ];


            $config_level2 = Db::table('db_warehouse_config')->field('id,config_id,parent_id')->where('id',$v1['parent_id'])->find();

            $config_level1 =  Db::table('db_warehouse_config')->where('id',$config_level2['parent_id'])->value('config_id');

            $tray_data['config1'][] = $config_level1;
            $tray_data['config1'][] = $config_level2['config_id'];


            //$value['config1'][1] = $config_level1['config_id'];
            // $value['config1'][0] = Db::table('db_warehouse_config')->where('id',$config_level1['parent_id'])->value('config_id');
            $tray_data['config2'] = $v1['config_id'];
            $tray_data['configData2'] = Db::table('db_warehouse_config')->field('name,config_id')
                ->where(['id'=>$v1['id'],'isstatus'=>1])->select()->toArray();
//            $value['warehouse_config_c_id'];


            if($tempNum >= $packing['packing_num'] * $packing['layup_num']){
                $tray_data['box_number'] = $packing['layup_num'];
                $tray_data['number'] = $packing['packing_num'] * $packing['layup_num'];
                $tempNum -= $tray_data['number'];
            }else{
                $tempSy = $tempNum % $packing['packing_num'];
                $tray_data['box_number'] =  $tempSy == 0
                    ? ($tempNum / $packing['packing_num'])
                    : ($tempNum > $packing['packing_num'] ? floor($tempNum / $packing['packing_num']) + 1 : 1);
                $tray_data['number'] = $tempNum;
            }



            $returnArr[] = $tray_data;
        }

        return [
            'tray_info'=>$returnArr,
//            'warehouse_config_info'=> (new Tray)->getTrayList(),
            'warehouse_config_info'=> $warehouse_config_list_tree
        ];
    }
}